package com.jh.paymentchannel.util.xjy;

import com.google.common.base.Preconditions;
import com.jh.paymentchannel.util.sdj.Coder;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Map.Entry;

import static com.google.common.base.Preconditions.checkArgument;


/**
 *
 * @since 1.0 2017-5-15
 * @version 2018/08/20 by Fuchun
 */
public class HttpClient {
	/**
	 * 目标地址
	 */
	private URL url;

	/**
	 * 通信连接超时时间
	 */
	private int connectionTimeout;

	/**
	 * 通信读超时时间
	 */
	private int readTimeOut;

	/**
	 * 通信结果
	 */
	private String result;

	/**
	 * 获取通信结果
	 */
	public String getResult() {
		return result;
	}

	/**
	 * 设置通信结果
	 */
	public void setResult(String result) {
		this.result = result;
	}

	/**
	 * 构造函数
	 */
	public HttpClient(String url, int connectionTimeout, int readTimeOut) throws MalformedURLException {
		this.url = new URL(url);
		this.connectionTimeout = connectionTimeout;
		this.readTimeOut = readTimeOut;
	}

	/**
	 * 发送信息到服务端
	 */
	public int send(Map<String, String> data, Charset charset) {
		try {
			HttpURLConnection httpURLConnection = createConnection(charset);
			if (null == httpURLConnection) {
				throw new Exception("创建联接失败");
			}
			String sendData = this.getRequestParamString(data, charset);
			this.requestServer(httpURLConnection, sendData, charset);
			this.result = this.response(httpURLConnection, charset);
			return httpURLConnection.getResponseCode();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/**
	 * 发送信息到服务端 GET方式
	 */
	public int sendGet(Charset charset) {
		try {
			HttpURLConnection httpURLConnection = createConnectionGet(charset);
			if (null == httpURLConnection) {
				throw new Exception("创建联接失败");
			}
			this.result = this.response(httpURLConnection, charset);
			return httpURLConnection.getResponseCode();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/**
	 * HTTP Post发送消息
	 */
	private void requestServer(final URLConnection connection, String message,
			Charset charset) {
		PrintStream out = null;
		try {
			connection.connect();
			out = new PrintStream(connection.getOutputStream(), false, charset.displayName());
			out.print(message);
			out.flush();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		} finally {
			if (null != out) {
				out.close();
			}
		}
	}

	/**
	 * 显示Response消息
	 */
	private String response(final HttpURLConnection connection, Charset charset)
			throws Exception {
		InputStream in = null;
		StringBuilder sb = new StringBuilder(1024);
		try {
			if (200 == connection.getResponseCode()) {
				in = connection.getInputStream();
				sb.append(new String(read(in), charset));
			} else {
				in = connection.getErrorStream();
				sb.append(new String(read(in), charset));
			}
			return sb.toString();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		} finally {
			if (null != in) {
				in.close();
			}
			if (null != connection) {
				connection.disconnect();
			}
		}
	}

	public static byte[] read(InputStream in) throws IOException {
		byte[] buf = new byte[1024];
		int length;
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		while ((length = in.read(buf, 0, buf.length)) > 0) {
			bout.write(buf, 0, length);
		}
		bout.flush();
		return bout.toByteArray();
	}

	/**
	 * 创建连接
	 */
	private HttpURLConnection createConnection(Charset charset)
			throws ProtocolException {
		HttpURLConnection httpURLConnection;
		try {
			httpURLConnection = (HttpURLConnection) url.openConnection();
		} catch (IOException e) {
			return null;
		}
		httpURLConnection.setConnectTimeout(this.connectionTimeout);// 连接超时时间
		httpURLConnection.setReadTimeout(this.readTimeOut);// 读取结果超时时间
		httpURLConnection.setDoInput(true); // 可读
		httpURLConnection.setDoOutput(true); // 可写
		httpURLConnection.setUseCaches(false);// 取消缓存
		httpURLConnection.setRequestProperty("Content-type",
				"application/x-www-form-urlencoded;charset=" + charset.displayName());
		httpURLConnection.setRequestMethod("POST");
		return httpURLConnection;
	}

	/**
	 * 创建连接
	 */
	private HttpURLConnection createConnectionGet(Charset charset)
			throws ProtocolException {
		HttpURLConnection httpURLConnection;
		try {
			httpURLConnection = (HttpURLConnection) url.openConnection();
		} catch (IOException e) {
			return null;
		}
		httpURLConnection.setConnectTimeout(this.connectionTimeout);// 连接超时时间
		httpURLConnection.setReadTimeout(this.readTimeOut);// 读取结果超时时间
		httpURLConnection.setUseCaches(false);// 取消缓存
		httpURLConnection.setRequestProperty("Content-type",
				"application/x-www-form-urlencoded;charset=" + charset.displayName());
		httpURLConnection.setRequestMethod("GET");
		return httpURLConnection;
	}

	/**
	 * 将Map存储的对象，转换为key=value&key=value的字符
	 */
	private String getRequestParamString(
	        Map<String, String> requestParam, Charset charset) {
		if (charset == null) {
            charset = StandardCharsets.UTF_8;
		}
		StringBuilder sf = new StringBuilder();
		String reqstr = "";
		if (null != requestParam && 0 != requestParam.size()) {
			for (Entry<String, String> en : requestParam.entrySet()) {
				try {
					sf.append(en.getKey()).append("=").append(null == en.getValue()
							|| "".equals(en.getValue()) ? ""
							: URLEncoder.encode(en.getValue(), charset.displayName())).append("&");
				} catch (UnsupportedEncodingException ex) {
				    // 不会发生这个异常，这里的 try catch 是非必要的
					throw new InternalError(ex);
				}
			}
			reqstr = sf.substring(0, sf.length() - 1);
		}
		return reqstr;
	}

}
